<script lang="ts" setup name="ManagePage">
import { reactive, ref } from 'vue'
import Sortable from 'sortablejs'
import { buildUUID } from 'iking-utils'
import { saveFile } from './download-file'
import { useFields } from './fields'
import { modelManage as api } from '@/MainApp/apis/manage-design'
import { copyValue } from '@/global/utils'

const { t } = useConfig()
const { msgSuccess, msgError } = useMessage()
const pageRef = ref<any>(null)
const tblData = ref<Array<any>>([])
const searchData = ref<any>({
  page: 1,
  rows: 15
})
const fields = ref([])
const countTotal = ref(0)
const loading = ref<boolean>(false)

useFields().then((res: any) => {
  fields.value = res
})

const search = async () => {
  const params = {
    ...searchData.value
  }

  const ret = await api.select(params)

  countTotal.value = ret.total
  tblData.value = ret.data
}

const handleAdd = () => {
  formModel.creationType = 'MANUALLY'
  enterWayMethods.open()
  // editMethods.open('add')
}

const handleEdit = (record: any) => {
  editMethods.open('update', record)
}

const handleDelete = async (record: any) => {
  const id = record.id
  const ret = await api.del(id)
  msgSuccess(ret.msg)
  search()
}

/**
 * 获取发布提示信息
 * @param row
 */
const publishTitle = (row: any) => {
  if (row.status === 'UNPUBLISHED')
    return '确认发布？'

  else if (row.status === 'PUBLISHING')
    return '发布中，请稍后再试！'

  else
    return '确认取消发布？'
}

/**
 * 发布
 */
const handlePublish = async (row: any) => {
  let operation = ''
  if (row.status === 'UNPUBLISHED')
    operation = 'publish'

  else if (row.status === 'PUBLISHING')
    operation = 'close'

  else
    operation = 'cancelPublish'

  if (operation === 'close')
    return

  let ret = null
  if (operation === 'publish')
    ret = await api.publish(row.id)

  else
    ret = await api.publishCancel(row.id)

  if (!ret.success) {
    msgError(ret.msg)
    return
  }

  msgSuccess(ret.msg)
  search()
}

/** 生成代码 begin */
const codeFormRef = ref<any>(null)
class CodeForm {
  packageName = ''
}
// 代码表单
const codeForm = reactive(new CodeForm())
// 代码对话框状态
const codeState = reactive({
  visible: false
})
// 代码对话框方法
const codeMethods = {
  open: () => {
    copyValue(codeForm, new CodeForm())
    codeFormRef.value?.resetFields()
    codeState.visible = true
  },
  close: () => {
    codeState.visible = false
  },
  submit: async () => {
    const rows = pageRef.value?.chooseList ?? []
    const params = {
      modelIds: rows.map((item: any) => item.id),
      // modelIds: ['111'],
      ...codeForm
    }
    const ret = await api.genCode(params)
    const { success, msg } = ret
    if (success === undefined) {
      saveFile(ret, { name: codeForm.packageName.replace('.', '-') })
      return
    }
    msgError(msg)
  }
}
/** 生成代码 end */

/** 录入方式选择 begin */
const enterWayState = reactive({
  visible: false
  // 'input' | 'datasource'
  // way: 'input'
})
const enterWayMethods = {
  open: () => {
    enterWayState.visible = true
  },
  close: () => {
    enterWayState.visible = false
  },
  next: () => {
    enterWayMethods.close()
    editMethods.open()
  }
}
/** 录入方式选择 end */

/** 新增、编辑对话框 begin */
const editFormRef = ref<any>(null)
// 业务模型字段信息
class Field {
  rowKey = `row${buildUUID()}`
  // 主键
  id = null
  // 字段名称
  name = ''
  // 字段类型
  // STRING,LIST,DATE,LOCAL_DATE_TIME,LOCAL_DATE,LOCAL_TIME,BOOLEAN,INT,DOUBLE,FLOAT
  type = 'STRING'
  // 字段说明
  remark = ''
  // 是否为数据库表字段
  dbTableField = ''
  // 数据库表字段长度
  length = '60'
  // VARCHAR,CHAR,TEXT,LONG_TEXT,BLOB,DATETIME,TIMESTAMP,INT,TINYINT,DOUBLE,FLOAT
  dbTableFieldType = 'VARCHAR'
  // 是否为查询条件
  queryField = true
  // 数据库表字段是否允许空值
  nullable = true
  // 查询类型
  // EQ,LIKE,IN,GT,GE,LT,LE
  compareType = 'LIKE'
  // 是否为从数据源同步过来的字段
  syncWithDatasource = false
}
// 关联模型
class SlaveModel {
  modelId = ''
  foreignKeyFieldId = ''
}

// 字段类型选项
const fieldTypeOptions = reactive([
  'STRING',
  'LIST',
  'DATE',
  'LOCAL_DATE_TIME',
  'LOCAL_DATE',
  'LOCAL_TIME',
  'BOOLEAN',
  'INT',
  'DOUBLE',
  'FLOAT'])

// 数据库表字段类型选项
const dbFieldTypeOptions = reactive([
  'VARCHAR', 'CHAR', 'TEXT', 'LONG_TEXT', 'BLOB', 'DATETIME', 'TIMESTAMP', 'INT', 'TINYINT', 'DOUBLE', 'FLOAT'
])

// 查询类型选项
const compareTypeOptions = reactive([
  'EQ', 'LIKE', 'IN', 'GT', 'GE', 'LT', 'LE'
])

/**
 * 模型数据源信息
 */
class ModelDatasourceInfo {
  creationType = ''
  datasourceId = ''
  syncTableName = ''
}

// 表单对象
class FormModel {
  // 主键
  id: string | null = null
  // 业务模型名称
  name = ''
  // 业务模型标识
  code = ''
  // 业务模型描述
  remark = ''
  // 模型创建类型,可用值:MANUALLY,SYNC_WITH_DATASOURCE
  creationType = 'MANUALLY'
  // 数据源编号
  datasourceId = ''
  // 同步表名
  syncTableName = ''
  // 业务模型字段信息
  fields: Field[] = [
    new Field()
  ]

  // 关联模型信息
  slaveModels: any[] = []
}

const formModel = reactive(new FormModel())

const editState = reactive<any>({
  title: '',
  operation: '',
  visible: false,
  activeNames: ['base', 'field'],
  modelOptions: [],
  // 数据源选项
  datasourceOptions: [],
  // 数据源对应的表格列表
  tableOptions: [],
  // 拖动排序对象
  sortable: null
})

const disableBaseInfo = computed(() => {
  return editState.operation === 'update'
    && formModel.creationType === 'SYNC_WITH_DATASOURCE'
    && !!formModel.datasourceId
    && !!formModel.syncTableName
})

const editMethods = {
  initModelOptions: async () => {
    const ret = await api.selectAll()
    if (!ret.success)
      return

    editState.modelOptions = ret.data
  },

  initTableOptions: async (datasourceId: string) => {
    const res = await api.listByDatasourceId(datasourceId)
    if (!res.success) {
      msgError(res.msg)
      return
    }
    editState.tableOptions = res.data
  },
  initDatasourceOptions: async () => {
    const res = await api.listAllDatasource()
    if (!res.success) {
      msgError(res.msg)
      return
    }
    editState.datasourceOptions = res.data

    if (formModel.datasourceId)
      editMethods.initTableOptions(formModel.datasourceId)
  },
  open: async (operation = 'add', record?: any) => {
    editState.operation = operation
    await editMethods.initModelOptions()
    const inputWay = formModel.creationType
    copyValue(formModel, new FormModel())
    codeFormRef.value?.resetFields()
    formModel.creationType = inputWay
    if (operation === 'update') {
      // TODO 将数据库里的设置数据赋值给设置器
      editState.title = '修改'
      record.fields?.forEach((item: any) => {
        item.rowKey = `row${buildUUID()}`
      })
      record.slaveModels.forEach((item: any) => {
        item.model = editState.modelOptions.find((m: any) => m.id === item.modelId)
      })
      copyValue(formModel, record)
    }
    else if (operation === 'add') {
      editState.title = '新增'
    }

    if (formModel.creationType === 'SYNC_WITH_DATASOURCE')
      editMethods.initDatasourceOptions()

    editState.visible = true

    setTimeout(() => {
      editMethods.setSort()
    }, 800)
  },
  close: () => {
    editState.visible = false
  },
  submit: async () => {
    let valid = false
    try {
      valid = await editFormRef.value?.validate()
    }
    catch (err) {
    }

    if (!valid)
      return

    const params = {
      ...formModel
    }
    params.fields.forEach((item: any, index: number) => {
      item.sortOrder = index
    })

    loading.value = true
    let ret = null
    if (editState.operation === 'add')
      ret = await api.add(params)
    else
      ret = await api.update(params)

    loading.value = false
    msgSuccess(ret.msg)
    editMethods.close()
    search()
  },
  addRow: (index?: number) => {
    if (index === undefined) {
      formModel.fields.push(new Field())
      return
    }

    formModel.fields.splice(index + 1, 0, new Field())
  },
  addModelRow(index?: number) {
    if (!formModel.slaveModels)
      formModel.slaveModels = []

    if (index === undefined) {
      formModel.slaveModels.push(new SlaveModel())
      return
    }

    formModel.slaveModels.splice(index + 1, 0, new SlaveModel())
  },
  remove: (index: number) => {
    if (formModel.fields.length === 1)
      return

    formModel.fields.splice(index, 1)
  },
  removeModelRow: (index: number) => {
    formModel.slaveModels.splice(index, 1)
  },
  setSlaveModel: (id: string, row: any) => {
    const target = editState.modelOptions.find((item: any) => item.id === id)
    row.model = target
  },
  handleTypeChange: (type: string, row: any) => {
    if (type === 'LIST')
      row.dbTableField = false

    else
      row.dbTableField = true
  },
  setSort: () => {
    const el: any = document.querySelectorAll('.model-manage-field-box .el-table__body-wrapper .el-table__body > tbody')[0]
    editState.sortable = new Sortable(el, {
      sort: true,
      handle: '.column-drag-handler',
      ghostClass: 'sortable-ghost',
      onEnd: ({ oldIndex, newIndex }: any) => {
        formModel.fields.splice(newIndex, 0, formModel.fields.splice(oldIndex, 1)[0])
      }
    })
  },
  handleDatasourceChange: (value: string) => {
    if (!value) {
      editState.tableOptions = []
      return
    }
    editMethods.initTableOptions(value)
  },
  handleSyncTableChange: (value: string) => {
    if (!value)
      return

    const target = editState.tableOptions.find((item: any) => item.code === value)
    editMethods.loadSyncTableModel(target)
  },
  loadSyncTableModel: (model: any) => {
    model.fields?.forEach((item: any) => {
      item.rowKey = `row${buildUUID()}`
    })
    const info = new ModelDatasourceInfo()
    copyValue(info, formModel)
    copyValue(formModel, model)
    copyValue(formModel, info)
  }
}

/** 新增、编辑对话框 end */

/** sql begin */
const sqlRef = ref<any>(null)
const sqlState = reactive({
  visible: false,
  code: ''
})
const sqlMethods = {
  open: async () => {
    let valid = false
    try {
      valid = await editFormRef.value?.validate()
    }
    catch (err) {
    }

    if (!valid)
      return

    const params = {
      ...formModel
    }

    const res = await api.sqlPreview(params)
    if (!res.success) {
      msgError(res.msg)
      return
    }
    sqlState.code = res.data
    sqlState.visible = true
  },
  copy: () => {
    sqlRef.value?.copyData()
  }
}
/** sql end */
</script>

<template>
  <IkPageMain fixed>
    <IkPageFull
      ref="pageRef"
      v-model="searchData"
      header-title="模型列表"
      :fields="fields"
      :table-data="tblData"
      :total="countTotal"
      :loading="loading"
      :search="search"
      :selection="true"
      row-key="id"
    >
      <template #headerRight>
        <el-button type="primary" @click="handleAdd">新增</el-button>
      </template>
      <template #selectionRight>
        <IkTooltip :content="t('生成代码')">
          <IkSvgIcon
            name="icon-xiazai"
            show-bg
            :width="40"
            size="big"
            type="primary"
            @click="codeMethods.open"
          />
        </IkTooltip>
      </template>
      <!-- <template #status="{ data }">
        <span>{{}}</span>
      </template> -->
      <template #operate="{ data }">
        <IkBtnContent :num="3">
          <el-popconfirm :title="publishTitle(data.row)" @confirm="handlePublish(data.row)">
            <template #reference>
              <!-- <IkTooltip content="发布"> -->
              <IkSvgIcon
                name="iksvg_chaosongren"
                show-bg
              />
              <!-- </IkTooltip> -->
            </template>
          </el-popconfirm>

          <IkTooltip :content="t('action.modify')">
            <IkSvgIcon
              name="iksvg_xiugai"
              show-bg

              @click="handleEdit(data.row)"
            />
          </IkTooltip>
          <IkTooltip :content="t('action.delete')">
            <el-popconfirm title="确定删除吗？" @confirm="handleDelete(data.row)">
              <template #reference>
                <IkSvgIcon
                  name="iksvg_shanchu1"
                  show-bg
                />
              </template>
            </el-popconfirm>
          </IkTooltip>
        </IkBtnContent>
      </template>
    </IkPageFull>

    <el-dialog v-model="enterWayState.visible" width="400px" title="录入方式">
      <el-radio-group v-model="formModel.creationType">
        <el-radio label="MANUALLY">手动录入</el-radio>
        <el-radio label="SYNC_WITH_DATASOURCE">数据源加载</el-radio>
      </el-radio-group>
      <template #footer>
        <el-button @click="enterWayMethods.close">取消</el-button>
        <el-button type="primary" :loading="loading" @click="enterWayMethods.next">
          确认
        </el-button>
      </template>
    </el-dialog>
    <el-dialog
      v-model="editState.visible"
      width="1360px"
      title="模型信息"
      center
      align-center
      append-to-body
    >
      <el-form
        v-if="editState.visible"
        ref="editFormRef"
        :label-width="0"
        :model="formModel"
      >
        <el-collapse v-model="editState.activeNames">
          <el-collapse-item title="基础信息" name="base">
            <el-row v-if="formModel.creationType === 'SYNC_WITH_DATASOURCE'">
              <el-col :span="12">
                <el-form-item :rules="[{ required: true, message: '请选择数据源' }]" label-width="100px" label="数据源">
                  <el-select v-model="formModel.datasourceId" :disabled="disableBaseInfo" @change="editMethods.handleDatasourceChange">
                    <el-option
                      v-for="item in editState.datasourceOptions"
                      :key="item.id"
                      :label="item.name"
                      :value="item.id"
                    />
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label-width="100px" label="数据源表">
                  <el-select
                    v-model="formModel.syncTableName"
                    :disabled="disableBaseInfo"
                    :rules="[{ required: true, message: '请选择数据源表' }]"
                    @change="editMethods.handleSyncTableChange"
                  >
                    <el-option
                      v-for="item in editState.tableOptions"
                      :key="item.code"
                      :label="item.label"
                      :value="item.code"
                    />
                  </el-select>
                </el-form-item>
              </el-col>
            </el-row>

            <el-form-item
              label-width="100px"
              prop="name"
              label="模型名称"
              :rules="[{ required: true, message: '请输入' }]"
            >
              <el-input v-model="formModel.name" :disabled="disableBaseInfo" :maxlength="45" />
            </el-form-item>
            <el-form-item
              label-width="100px"
              prop="code"
              label="模型标识"
              :rules="[{ required: true, message: '请输入' }]"
            >
              <el-input v-model="formModel.code" :disabled="disableBaseInfo" :maxlength="45" />
            </el-form-item>
            <el-form-item label-width="100px" prop="remark" label="模型描述">
              <el-input
                v-model="formModel.remark"
                :disabled="disableBaseInfo"
                type="textarea"
                :maxlength="200"
              />
            </el-form-item>
          </el-collapse-item>
          <el-collapse-item title="字段信息" name="field">
            <div class="model-manage-field-box">
              <el-table :data="formModel.fields" border row-key="rowKey">
                <el-table-column label="排序" width="58">
                  <div>
                    <IkSvgIcon name="iksvg_paixu" class="column-drag-handler" />
                  </div>
                </el-table-column>
                <el-table-column min-width="110px" prop="name" label="字段名">
                  <template #default="{ row, $index }">
                    <el-form-item
                      :show-message="false"
                      :label-width="0"
                      :rules="[{ required: true, message: '请输入' }]"
                      :prop="`fields.${$index}.name`"
                    >
                      <el-input v-model="row.name" :disabled="row.syncWithDatasource" :maxlength="45" />
                    </el-form-item>
                  </template>
                </el-table-column>
                <el-table-column width="190px" prop="type" label="字段类型">
                  <template #default="{ row, $index }">
                    <el-form-item :show-message="false" :prop="`fields.${$index}.type`">
                      <el-select v-model="row.type" :disabled="row.syncWithDatasource" @change="editMethods.handleTypeChange($event, row)">
                        <el-option
                          v-for="item in fieldTypeOptions"
                          :key="item"
                          :label="item"
                          :value="item"
                        />
                      </el-select>
                    </el-form-item>
                  </template>
                </el-table-column>
                <el-table-column min-width="150px" prop="remark" label="字段说明">
                  <template #default="{ row, $index }">
                    <el-form-item :show-message="false" :prop="`fields.${$index}.remark`">
                      <el-input v-model="row.remark" :disabled="row.syncWithDatasource" :maxlength="60" />
                    </el-form-item>
                  </template>
                </el-table-column>
                <el-table-column
                  align="center"
                  width="110px"
                  prop="dbTableField"
                  label="数据库字段"
                >
                  <template #default="{ row, $index }">
                    <el-form-item
                      :show-message="false"

                      :prop="`fields.${$index}.dbTableField`"
                    >
                      <el-switch v-model="row.dbTableField" :disabled="row.type === 'LIST' || row.syncWithDatasource" />
                    <!-- <IkSvgIcon v-if="row.dbTableField" name="iksvg_shezhi" /> -->
                    </el-form-item>
                  </template>
                </el-table-column>
                <el-table-column prop="length" label="字段长度">
                  <template #default="{ row, $index }">
                    <el-form-item :show-message="false" :prop="`fields.${$index}.length`">
                      <el-input-number
                        v-model="row.length"
                        :disabled="row.syncWithDatasource"
                        :min="0"
                        :controls="false"
                      />
                    </el-form-item>
                  </template>
                </el-table-column>
                <el-table-column width="150px" prop="dbTableFieldType" label="数据库字段类型">
                  <template #default="{ row, $index }">
                    <el-form-item :show-message="false" :prop="`fields.${$index}.dbTableFieldType`">
                      <el-select v-model="row.dbTableFieldType" :disabled="row.syncWithDatasource">
                        <el-option
                          v-for="item in dbFieldTypeOptions"
                          :key="item"
                          :label="item"
                          :value="item"
                        />
                      </el-select>
                    </el-form-item>
                  </template>
                </el-table-column>
                <el-table-column
                  align="center"
                  width="100px"
                  prop="nullable"
                  label="允许为空"
                >
                  <template #default="{ row, $index }">
                    <el-form-item :show-message="false" :prop="`fields.${$index}.nullable`">
                      <el-switch v-model="row.nullable" :disabled="row.syncWithDatasource" />
                    </el-form-item>
                  </template>
                </el-table-column>
                <el-table-column
                  align="center"
                  width="100px"
                  prop="queryField"
                  label="查询条件"
                >
                  <template #default="{ row, $index }">
                    <el-form-item :show-message="false" :prop="`fields.${$index}.queryField`">
                      <el-switch v-model="row.queryField" />
                    </el-form-item>
                  </template>
                </el-table-column>
                <el-table-column
                  min-width="120px"
                  prop="compareType"
                  label="查询比较类型"
                >
                  <template #default="{ row, $index }">
                    <el-form-item :show-message="false" :prop="`fields.${$index}.compareType`">
                      <el-select v-model="row.compareType">
                        <el-option
                          v-for="item in compareTypeOptions"
                          :key="item"
                          :label="item"
                          :value="item"
                        />
                      </el-select>
                    </el-form-item>
                  </template>
                </el-table-column>

                <el-table-column
                  width="68px"
                  align="center"
                  label="操作"
                >
                  <template #default="{ row, $index }">
                    <IkSvgIcon
                      v-if="!row.syncWithDatasource"
                      :start-margin="false"
                      name="iksvg_shanchu1"
                      show-bg
                      @click="editMethods.remove($index)"
                    />
                  </template>
                </el-table-column>
              </el-table>
              <el-button class="width-full" style="margin-top: 4px;" @click="editMethods.addRow()">
                <IkSvgIcon
                  name="iksvg_xinzeng"
                />
              </el-button>
            </div>
          </el-collapse-item>
          <el-collapse-item title="关联模型信息" name="model">
            <div class="model-manage-field-box">
              <el-table :data="formModel.slaveModels" border>
                <el-table-column min-width="110px" prop="modelId" label="模型">
                  <template #default="{ row, $index }">
                    <el-form-item
                      :show-message="false"
                      :label-width="0"
                      :rules="[{ required: true, message: '请选择' }]"
                      :prop="`slaveModels.${$index}.modelId`"
                    >
                      <el-select v-model="row.modelId" @change="editMethods.setSlaveModel($event, row)">
                        <el-option
                          v-for="item in editState.modelOptions"
                          :key="item.id"
                          :value="item.id"
                          :label="item.name"
                        />
                      </el-select>
                    </el-form-item>
                  </template>
                </el-table-column>
                <el-table-column min-width="110px" prop="foreignKeyFieldId" label="外键字段">
                  <template #default="{ row, $index }">
                    <el-form-item
                      :show-message="false"
                      :label-width="0"
                      :rules="[{ required: true, message: '请选择' }]"
                      :prop="`slaveModels.${$index}.foreignKeyFieldId`"
                    >
                      <el-select v-model="row.foreignKeyFieldId">
                        <el-option
                          v-for="item in row.model?.fields ?? []"
                          :key="item.id"
                          :value="item.id"
                          :label="item.name"
                        />
                      </el-select>
                    </el-form-item>
                  </template>
                </el-table-column>
                <el-table-column
                  width="68px"
                  prop="nullable"
                  align="center"
                  label="操作"
                >
                  <template #default="{ $index }">
                    <IkSvgIcon
                      :start-margin="false"
                      name="iksvg_shanchu1"
                      show-bg
                      @click="editMethods.removeModelRow($index)"
                    />
                  </template>
                </el-table-column>
              </el-table>
              <el-button class="width-full" style="margin-top: 4px;" @click="editMethods.addModelRow()">
                <IkSvgIcon name="iksvg_xinzeng" />
              </el-button>
            </div>
          </el-collapse-item>
        </el-collapse>
      </el-form>
      <template #footer>
        <el-button @click="editMethods.close">取消</el-button>
        <el-button type="primary" :loading="loading" @click="sqlMethods.open">
          SQL
        </el-button>
        <el-button type="primary" :loading="loading" @click="editMethods.submit">
          确认
        </el-button>
      </template>
    </el-dialog>
    <el-dialog
      v-model="sqlState.visible"
      title="查看 SQL"
      append-to-body
      :modal="false"
    >
      <div class="code-box">
        <div class="code-box-action">
          <el-button type="primary" link @click="sqlMethods.copy">复制</el-button>
        </div>
        <IkMonacoEditor ref="sqlRef" language="sql" :code="sqlState.code" />
      </div>
    </el-dialog>
    <!-- 生成代码 -->
    <el-dialog
      v-model="codeState.visible"
      append-to-body
      width="500px"
      title="代码生成"
    >
      <el-form ref="codeFormRef" :model="codeForm">
        <el-form-item label="代码包名" prop="packageName" :rules="[{ required: true, message: '请输入' }]">
          <el-input v-model="codeForm.packageName" :maxlength="45" placeholder="请输入" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="codeMethods.close">取消</el-button>
        <el-button type="primary" :loading="loading" @click="codeMethods.submit">
          确认
        </el-button>
      </template>
    </el-dialog>
  </IkPageMain>
</template>

<style scoped lang="scss">
.code-box{
  margin-top: -20px;
}

.code-box-action{
  text-align: right;
}

:deep(.el-table__inner-wrapper .el-form-item){
  margin-bottom: 0;
}

:deep(.code-box .datav-editor){
  border-radius: 4px;
}

.model-manage-field-box{
  :deep(.el-table__body-wrapper){
    border-bottom: var(--el-table-border);
  }
}
</style>
